package game.games.rpg;

import game.games.rpg.magic.AbstractBuff;
import game.gfx.ColoredChar;
import game.gfx.Colors;
import game.gfx.ConsoleColor;
import game.unicode.GeometricShapes;

import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Monster extends AbstractColoredCharRenderer implements IColoredCharRenderer
{
    public static final int MAX_NAME_LENGTH  = 16;
    public static final int MAX_LEVEL        = 99;
    
    private Direction       lookingDirection = Direction.NORTH;
    private int             maxHealth;
    private int             health;
    private int             attack;
    private int             level = 1;
    
    private Map<Class<? extends AbstractBuff>, AbstractBuff> buffs = new HashMap<Class<? extends AbstractBuff>, AbstractBuff>();
    
    public Monster(char body, ConsoleColor color, int health, int attack)
    {
        super(body, color);
        this.maxHealth = health;
        this.health = health;
        this.attack = attack;
    }
    
    public Monster()
    {
        this('?', new ConsoleColor(Colors.green, Colors.pink), 0, 0);
    }
    
    @Override
    public ColoredChar getChar()
    {
        ColoredChar c = super.getChar();
        if (isAlive() == false)
        {
            c.setChar(GeometricShapes.RECTANGLE_FULL_CIRCLE);
            c.setConsoleColor(new ConsoleColor(Colors.dark_slate_gray, Colors.black));
        }
        return c;
    }
    
    public Direction getLookingDirection()
    {
        return lookingDirection;
    }
    
    public void setLookingDirection(Direction lookingDirection)
    {
        this.lookingDirection = lookingDirection;
    }
    
    public void setLookingDirectionByKeyCode(int keyCode)
    {
        switch (keyCode)
        {
            case KeyEvent.VK_LEFT:
            {
                setLookingDirection(Direction.WEST);
                break;
            }
            case KeyEvent.VK_RIGHT:
            {
                setLookingDirection(Direction.EAST);
                break;
            }
            case KeyEvent.VK_UP:
            {
                setLookingDirection(Direction.NORTH);
                break;
            }
            case KeyEvent.VK_DOWN:
            {
                setLookingDirection(Direction.SOUTH);
                break;
            }
        }
    }
    
    public int getMaxHealth()
    {
        return maxHealth;
    }
    
    public void setMaxHealth(int maxHealth)
    {
        this.maxHealth = maxHealth;
    }
    
    public int getHealth()
    {
        return health;
    }
    
    public void setHealth(int health)
    {
        if (health < 0)
        {
            health = 0;
        }
        this.health = health;
    }
    
    public boolean isAlive()
    {
        return health > 0;
    }
    
    public int getAttack()
    {
        return attack;
    }
    
    public void setAttack(int attack)
    {
        this.attack = attack;
    }
    
    public int getLevel()
    {
        return level;
    }
    
    public void setLevel(int level)
    {
        this.level = level;
    }
    
    public <T extends AbstractBuff> void addBuff(T fireDamageBuff)
    {
        buffs.put((Class<? extends AbstractBuff>) fireDamageBuff.getClass(), fireDamageBuff);
    }
    
    @SuppressWarnings("unchecked")
    public <T extends AbstractBuff> T getBuff(Class<T> clazz)
    {
        return (T) buffs.get(clazz);
    }

    public void removeBuff(Class<? extends AbstractBuff> clazz)
    {
        buffs.remove(clazz);
    }

    public void checkBuffs(int currentTick)
    {
        synchronized (buffs)
        {
            List<AbstractBuff> inactive = new ArrayList<AbstractBuff>();
            for (AbstractBuff buff : buffs.values())
            {
                if (buff.isActive(currentTick))
                {
                    buff.next(currentTick);
                }
                else
                {
                    inactive.add(buff);
                }
            }
            for (AbstractBuff t : inactive)
            {
                removeBuff(t.getClass());
            }
        }
    }
}
